﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Twodi.Screen;
using Microsoft.Xna.Framework;
using Twodi.Implemented;
using Pong.Components;
using Microsoft.Xna.Framework.Audio;
using System.Xml.Linq;
using Microsoft.Xna.Framework.Input;
using Twodi.Utility;
using Twodi.Enums;
using Microsoft.Xna.Framework.Graphics;
using Twodi.Input;

namespace MonoPong.Components
{
    public class GameScreen : Screen
    {
        #region Interface

        public int WindowWidth;
        public int WindowHeight;

        DrawableLine LeftLine;
        DrawableLine RightLine;
        DrawableLine CenterLine;

        Label LeftScore;
        Label RightScore;

        #endregion

        #region Pads

        public int PadWidth;
        public int PadHeight;

        Pad LeftPad;
        Pad RightPad;

        #endregion

        #region Ball

        Ball Ball;

        #endregion

        #region Sounds

        SoundEffect Background;
        SoundEffectInstance BackgroundInstance;

        SoundEffect Ping;
        SoundEffect Pong;
        SoundEffect Point;
        bool ping = false;

        #endregion

        public GameScreen(Game game)
            : base(game)
        {

        }

        public override void Initialize()
        {
            XElement videoConfig = XDocument.Load(@"GameConfig.xml").Element("GameConfig").Element("VideoConfig");

            WindowWidth = int.Parse(videoConfig.Attribute("Width").Value);
            WindowHeight = int.Parse(videoConfig.Attribute("Height").Value);

            base.Initialize();
        }

        protected override void LoadContent()
        {
            Background = Game.Content.Load<SoundEffect>(GameResources.SFX_Background);
            BackgroundInstance = Background.CreateInstance();
            BackgroundInstance.Volume = 0.25f;

            Ping = Game.Content.Load<SoundEffect>(GameResources.SFX_Ping);
            Pong = Game.Content.Load<SoundEffect>(GameResources.SFX_Pong);
            Point = Game.Content.Load<SoundEffect>(GameResources.SFX_Point);

            CreateScore();
            CreatePads();
            CreateLines();
            CreateBall();

            base.LoadContent();
        }

        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update logic here
            BackgroundInstance.Play();
            LeftPad.Handle(GlobalInput.Keyboard);
            RightPad.Handle(GlobalInput.Keyboard);

            bool left = Ball.Bounds.Intersects(LeftPad.Bounds);
            bool right = Ball.Bounds.Intersects(RightPad.Bounds);

            if (left || right)
            {
                Ball.Velocity = new Vector2(-Ball.Velocity.X, Ball.Velocity.Y);

                ping = !ping;
                if (ping)
                {
                    Ping.Play();
                }
                else
                {
                    Pong.Play();
                }

                if (left)
                {
                    Ball.Position = new Vector2(Ball.Position.X + (LeftPad.Bounds.Right - Ball.Bounds.Left), Ball.Position.Y);
                }
                else if (right)
                {
                    Ball.Position = new Vector2(Ball.Position.X - (Ball.Bounds.Right - RightPad.Bounds.Left), Ball.Position.Y);
                };
            }

            base.Update(gameTime);
        }

        private void CreateScore()
        {
            LeftScore = new Label(Game.Content.Load<SpriteFont>("Arial"), this.Game)
            {
                SpriteBatch = SpriteBatch,
                Text = "0",
                Color = Color.White
            };

            LeftScore.Position = new Vector2((WindowWidth * 0.25f) - LeftScore.Size.X / 2, 0);

            RightScore = new Label(Game.Content.Load<SpriteFont>(GameResources.FNT_Arial_40), this.Game)
            {
                SpriteBatch = SpriteBatch,
                Text = "0",
                Color = Color.White
            };

            RightScore.Position = new Vector2((WindowWidth * 0.75f) - RightScore.Size.X / 2, 0);

            this.Components.Add(LeftScore);
            this.Components.Add(RightScore);
        }

        private void CreateBall()
        {
            XElement ballConfig = XDocument.Load(@"GameConfig.xml").Element("GameConfig").Element("BallConfig");

            Ball = new Ball(int.Parse(ballConfig.Attribute("Radius").Value), Color.White, this.Game)
            {
                SpriteBatch = SpriteBatch,
                Limits = this.GraphicsDevice.Viewport.Bounds
            };

            Ball.Velocity *= int.Parse(ballConfig.Attribute("Velocity").Value);
            Ball.Position = Helper.MiddlePosition(WindowWidth, WindowHeight, Ball.Size.X, Ball.Size.Y);

            Ball.LimitedProperties.TouchLimits += (sender, e) =>
            {
                if (e.Exit == Direction.West)
                {
                    RightScore.Text = (int.Parse(RightScore.Text) + 1).ToString();
                    Ball.Position = Helper.MiddlePosition(WindowWidth, WindowHeight, Ball.Size.X, Ball.Size.Y);
                    Point.Play();
                }
                else if (e.Exit == Direction.East)
                {
                    LeftScore.Text = (int.Parse(LeftScore.Text) + 1).ToString();
                    Ball.Position = Helper.MiddlePosition(WindowWidth, WindowHeight, Ball.Size.X, Ball.Size.Y);
                    Point.Play();
                }
            };

            this.Components.Add(Ball);
        }

        private void CreatePads()
        {
            XElement padConfig = XDocument.Load(@"GameConfig.xml").Element("GameConfig").Element("PadConfig");

            PadWidth = int.Parse(padConfig.Attribute("Width").Value);
            PadHeight = int.Parse(padConfig.Attribute("Height").Value);
            int PadVelocity = int.Parse(padConfig.Attribute("Velocity").Value);

            LeftPad = new Pad(PadWidth, PadHeight, Color.White, this.Game)
            {
                SpriteBatch = SpriteBatch,
                Position = new Vector2(0, (WindowHeight - PadHeight) / 2),
                Limits = this.GraphicsDevice.Viewport.Bounds,
                Velocity = PadVelocity
            };

            RightPad = new Pad(PadWidth, PadHeight, Color.White, this.Game)
            {
                SpriteBatch = SpriteBatch,
                Position = new Vector2(WindowWidth - PadWidth, (WindowHeight - PadHeight) / 2),
                Limits = this.GraphicsDevice.Viewport.Bounds,
                Velocity = PadVelocity
            };

            PlayerOneControlEvent(LeftPad);
            PlayerTwoControlEvent(RightPad);

            this.Components.Add(LeftPad);
            this.Components.Add(RightPad);
        }

        private void CreateLines()
        {
            LeftLine = new DrawableLine(this.Game)
            {
                SpriteBatch = SpriteBatch,
                Begin = new Vector2(PadWidth, 0),
                End = new Vector2(PadWidth, WindowHeight)
            };

            RightLine = new DrawableLine(this.Game)
            {
                SpriteBatch = SpriteBatch,
                Begin = new Vector2(WindowWidth - PadWidth, 0),
                End = new Vector2(WindowWidth - PadWidth, WindowHeight)
            };

            CenterLine = new DrawableLine(this.Game)
            {
                SpriteBatch = SpriteBatch,
                Begin = new Vector2(WindowWidth / 2, 0),
                End = new Vector2(WindowWidth / 2, WindowHeight)
            };

            this.Components.Add(LeftLine);
            this.Components.Add(RightLine);
            this.Components.Add(CenterLine);
        }

        private void PlayerTwoControlEvent(Pad pad)
        {
            pad.AddControlEvent(Keys.Up, Keys.Down);
        }

        private void PlayerOneControlEvent(Pad pad)
        {
            pad.AddControlEvent(Keys.W, Keys.S);
        }
    }
}
